/**
 * 
 */
package com.primestone.cim.meterreadings;

import java.util.List;

import javax.xml.ws.Holder;

import ch.iec.tc57._2011.getmeterreadingsmessage.GetMeterReadingsRequestType;
import ch.iec.tc57._2011.getmeterreadingsmessage.MeterReadingsFaultMessageType;
import ch.iec.tc57._2011.meterreadings.FaultMessage;
import ch.iec.tc57._2011.meterreadings.MeterReading;
import ch.iec.tc57._2011.meterreadings.MeterReadings;
import ch.iec.tc57._2011.schema.message.HeaderType;
import ch.iec.tc57._2011.schema.message.MessageProperty;
import ch.iec.tc57._2011.schema.message.OptionType;
import ch.iec.tc57._2011.schema.message.ReplyType;

import com.primestone.cim.util.CollectionUtil;
import com.primestone.cim.util.NumberUtil;
import com.primestone.cim.util.StringUtil;
import com.primestone.cim.util.enums.CIMNoun;
import com.primestone.cim.util.enums.CIMVerb;
import com.primestone.cim.util.enums.MessageEnum;
import com.primestone.cim.util.enums.ResultEnum;

/**
 * @author cesar.mateus
 *
 */
public class Validator {

	/**
	 * 
	 * @param message
	 * @return
	 */
	public static FaultMessage composeFault(String message) {
		MeterReadingsFaultMessageType meterReadingsFaultMessage = new MeterReadingsFaultMessageType();
		ReplyType replyType = new ReplyType();
		replyType.setResult(ResultEnum.FAILED.getName());
		meterReadingsFaultMessage.setReply(replyType);			
		return new FaultMessage(message, meterReadingsFaultMessage);
	}

	/**
	 * 
	 * @param properties
	 * @return
	 */
	public static boolean existPwd( List<MessageProperty> properties) {
		boolean existPwd = false;
		for (MessageProperty messageProperty : properties) {
			if (StringUtil.safe(messageProperty.getName()) && StringUtil.safe(messageProperty.getValue()) 
					&& messageProperty.getName().equals(StringUtil.PWD_PROP_NAME) ) {
				existPwd = true;
				break;
			}
		}
		return existPwd;
	}

	/**
	 * 
	 * @param meterReadings
	 * @return
	 */
	public static boolean isEmptyMeterReadings(MeterReadings meterReadings) {
		List<MeterReading> meterReadingList = meterReadings.getMeterReading();
		if (meterReadingList.size() == 1) {
			MeterReading meterReading = meterReadingList.get(0);
			if (CollectionUtil.safe(meterReading.getEndDeviceEvents()) || CollectionUtil.safe(meterReading.getIntervalBlocks()) || CollectionUtil.safe(meterReading.getReadings()) ) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * 
	 * @param request
	 * @return
	 */
	public static FaultMessage validateBasicRequest(GetMeterReadingsRequestType request) {
		FaultMessage faultMessage = null;
		if (request == null) {
			faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_INFO.getDescription());			
		} else if (request.getOption() == null) {
			faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_OPTIONS.getDescription());
		}
		return faultMessage;
	}
	
	/**
	 * 
	 * @param header
	 * @return
	 */
	public static FaultMessage validateHeader(Holder<HeaderType> header) {
		if (header == null || header.value == null) {
			return Validator.composeFault(MessageEnum.INCOMPLETE_HEADER_INFO.getDescription());
		}

		if ( header.value.getUser() == null || !StringUtil.safe(header.value.getUser().getUserID()) || 
				!CollectionUtil.safe(header.value.getProperty()) || !existPwd(header.value.getProperty()) ) {
			return Validator.composeFault(MessageEnum.INCOMPLETE_USER_INFO.getDescription());
		}

		if (!StringUtil.safe(header.value.getVerb())) {
			return Validator.composeFault(MessageEnum.INCOMPLETE_VERB_INFO.getDescription());
		} else if (!header.value.getVerb().equals(CIMVerb.GET_VERB.getVerb())) {
			return Validator.composeFault(MessageEnum.INCORRECT_VERB_INFO.getDescription());
		} else if (!StringUtil.safe(header.value.getNoun())) {
			return Validator.composeFault(MessageEnum.INCOMPLETE_NOUN_INFO.getDescription());
		} else if (!header.value.getNoun().equals(CIMNoun.METER_READING_NOUN.getNoun())) {
			return Validator.composeFault(MessageEnum.INCORRECT_NOUN_INFO.getDescription());
		}
		return null;
	}

	/**
	 * 
	 * @param request
	 * @param onlySocDev 
	 * @return
	 */
	public static FaultMessage validateRequest(GetMeterReadingsRequestType request, boolean onlySocDev) {
		FaultMessage faultMessage = validateBasicRequest(request);
		if (faultMessage == null) {
			List<OptionType> options = request.getOption();
			Byte isError = 0;
			boolean incompleteTop = true;
			boolean incompleteBatch = true;
			boolean incompleteVarType = true;
			boolean onlyNew = false;
			for (OptionType option : options) {
				if ( option != null && StringUtil.safe(option.getName()) ) {
					
					if (!onlySocDev) {
						if (option.getName().equals(StringUtil.ONLY_NEW_READINGS)) {
							if (StringUtil.safe(option.getValue())) {
								onlyNew = true;
							}
						} else if (option.getName().equals(StringUtil.BATCH_NAME)) {
							if (!StringUtil.safe(option.getValue())) {
								faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_BATCH.getDescription());
								break;
							}
							incompleteBatch = false;
						} else if (option.getName().equals(StringUtil.TOP_NAME)) {
							if (!StringUtil.safe(option.getValue())) {
								faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_TOP.getDescription());
								break;
							}
							incompleteTop = false;
						} else if (option.getName().equals(StringUtil.VARTYPE_FIELD_NAME)) {
							if (!StringUtil.safe(option.getValue())) {
								faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_VARTYPE.getDescription());
								break;
							} else if(!option.getValue().contains(StringUtil.VARTYPE_LP) && 
									  !option.getValue().contains(StringUtil.VARTYPE_REG) &&
									  !option.getValue().contains(StringUtil.VARTYPE_EVE) ) {
								faultMessage = Validator.composeFault(MessageEnum.INCORRECT_REQUEST_VARTYPE.getDescription());
								break;
							}
							incompleteVarType = false;
						}	
					}
					
					// El contenido de estos options puede ser una cadena separada por comas o un solo valor.
					if (option.getName().equals(StringUtil.SOCKET_FIELD_NAME)) {
						if (!StringUtil.safe(option.getValue())) {
							isError++;
						} else if (onlyNew) {
							faultMessage = Validator.composeFault(MessageEnum.INCORRECT_REQUEST_SOCKET_OR_DEVICE.getDescription());
							break;
						}
					} else if (option.getName().equals(StringUtil.DEVICE_FIELD_NAME)) {
						if (!StringUtil.safe(option.getValue())) {
							isError++;
						}
					}
				}
				
				if (!isError.equals(NumberUtil.ZERO)) {
					faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_SOCKET_OR_DEVICE.getDescription());
					break;
				}
			}
			
			if (!onlySocDev) {
				if (faultMessage == null) {
					if (incompleteTop) {
						faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_TOP.getDescription());
					} else if (incompleteVarType) {
						faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_VARTYPE.getDescription());
					} else if (incompleteBatch) {
						faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_BATCH.getDescription());
					}
				}
				
				if (faultMessage == null && !onlyNew) {
					if (request.getStartTime() == null) {
						faultMessage = Validator.composeFault(MessageEnum.INCOMPLETE_REQUEST_START_TIME.getDescription());
					}
				}	
			}
		}

		return faultMessage;
	}
	
}